home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / dirfns.cc < prev    next >
C/C++ Source or Header  |  1997-05-26  |  14KB  |  710 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. /*
  24.  
  25. The functions listed below were adapted from a similar functions
  26. from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
  27. Free Software Foundation, Inc.
  28.  
  29.   polite_directory_format  absolute_pathname
  30.   base_pathname
  31.   make_absolute            pathname_backup
  32.   change_to_directory      get_working_directory
  33.  
  34. */ 
  35.  
  36. #ifdef HAVE_CONFIG_H
  37. #include <config.h>
  38. #endif
  39.  
  40. #include <cerrno>
  41. #include <cstdio>
  42. #include <cstddef>
  43. #include <cstdlib>
  44. #include <cstring>
  45.  
  46. #include <string>
  47.  
  48. #include <strstream.h>
  49.  
  50. #ifdef HAVE_UNISTD_H
  51. #ifdef HAVE_SYS_TYPES_H
  52. #include <sys/types.h>
  53. #endif
  54. #include <unistd.h>
  55. #endif
  56.  
  57. #include "oct-glob.h"
  58. #include "str-vec.h"
  59.  
  60. #include "defun.h"
  61. #include "dir-ops.h"
  62. #include "dirfns.h"
  63. #include "error.h"
  64. #include "file-ops.h"
  65. #include "gripes.h"
  66. #include "help.h"
  67. #include "oct-obj.h"
  68. #include "pager.h"
  69. #include "pathlen.h"
  70. #include "procstream.h"
  71. #include "pt-plot.h"
  72. #include "sysdep.h"
  73. #include "toplev.h"
  74. #include "unwind-prot.h"
  75. #include "utils.h"
  76. #include "variables.h"
  77.  
  78. // The current working directory.
  79. string Vcurrent_directory;
  80.  
  81. // Non-zero means follow symbolic links that point to directories just
  82. // as if they are real directories.
  83. static int follow_symbolic_links = 1;
  84.  
  85. // Non-zero means that pwd always give verbatim directory, regardless
  86. // of symbolic link following.
  87. static int verbatim_pwd = 1;
  88.  
  89. // Remove the last N directories from PATH.  Do not PATH blank.
  90. // PATH must contain enough space for MAXPATHLEN characters.
  91.  
  92. static void
  93. pathname_backup (string& path, int n)
  94. {
  95.   if (path.empty ())
  96.     return;
  97.  
  98.   size_t i = path.length () - 1;
  99.  
  100.   while (n--)
  101.     {
  102.       while (path[i] == '/' && i > 0)
  103.     i--;
  104.  
  105.       while (path[i] != '/' && i > 0)
  106.     i--;
  107.  
  108.       i++;
  109.     }
  110.  
  111.   path.resize (i);
  112. }
  113.  
  114. // Return a pretty pathname.  If the first part of the pathname is the
  115. // same as $HOME, then replace that with `~'.
  116.  
  117. string
  118. polite_directory_format (const string& name)
  119. {
  120.   string retval;
  121.  
  122.   size_t len = Vhome_directory.length ();
  123.  
  124.   if (len > 1 && Vhome_directory.compare (name, 0, len) == 0
  125.       && (name.length () == len || name[len] == '/'))
  126.     {
  127.       retval = "~";
  128.       retval.append (name.substr (len));
  129.     }
  130.   else
  131.     retval = name;
  132.  
  133.   return retval;
  134. }
  135.  
  136. // Return 1 if STRING contains an absolute pathname, else 0.
  137.  
  138. static int
  139. absolute_pathname (const string& s)
  140. {
  141.   if (s.empty ())
  142.     return 0;
  143.  
  144.   if (s[0] == '/')
  145.     return 1;
  146.  
  147.   if (s[0] == '.')
  148.     {
  149.       if (s[1] == '\0' || s[1] == '/')
  150.     return 1;
  151.  
  152.       if (s[1] == '.')
  153.     if (s[2] == '\0' || s[2] == '/')
  154.       return 1;
  155.     }
  156.  
  157.   return 0;
  158. }
  159.  
  160. // Return the `basename' of the pathname in STRING (the stuff after
  161. // the last '/').  If STRING is not a full pathname, simply return it.
  162.  
  163. string
  164. base_pathname (const string& s)
  165. {
  166.   if (! absolute_pathname (s))
  167.     return s;
  168.  
  169.   size_t pos = s.rfind ('/');
  170.  
  171.   if (pos == NPOS)
  172.     return s;
  173.   else
  174.     return s.substr (pos+1);
  175. }
  176.  
  177. // Turn STRING (a pathname) into an absolute pathname, assuming that
  178. // DOT_PATH contains the symbolic location of '.'.
  179.  
  180. string
  181. make_absolute (const string& s, const string& dot_path)
  182. {
  183. #if defined (__EMX__)
  184.   if (s.length () > 1 && s[1] == ':')
  185.     return s;
  186. #endif
  187.  
  188.   if (dot_path.empty () || s[0] == '/' || s.empty ())
  189.     return s;
  190.  
  191.   string current_path = dot_path;
  192.  
  193.   if (current_path.empty ())
  194.     current_path = "./";
  195.  
  196.   size_t pos = current_path.length () - 1;
  197.  
  198.   if (current_path[pos] != '/')
  199.     current_path.append ("/");
  200.  
  201.   size_t i = 0;
  202.   size_t slen = s.length ();
  203.  
  204.   while (i < slen)
  205.     {
  206.       if (s[i] == '.')
  207.     {
  208.       if (i + 1 == slen)
  209.         return current_path;
  210.  
  211.       if (s[i+1] == '/')
  212.         {
  213.           i += 2;
  214.           continue;
  215.         }
  216.  
  217.       if (s[i+1] == '.' && (i + 2 == slen || s[i+2] == '/'))
  218.         {
  219.           i += 2;
  220.  
  221.           if (i != slen)
  222.         i++;
  223.  
  224.           pathname_backup (current_path, 1);
  225.  
  226.           continue;
  227.         }
  228.     }
  229.  
  230.       size_t tmp = s.find ('/', i);
  231.  
  232.       if (tmp == NPOS)
  233.     {
  234.       current_path.append (s, i, tmp-i);
  235.       break;
  236.     }
  237.       else
  238.     {
  239.       current_path.append (s, i, tmp-i+1);
  240.       i = tmp + 1;
  241.     }
  242.     }
  243.  
  244.   return current_path;
  245. }
  246.  
  247. // Return a consed string which is the current working directory.
  248. // FOR_WHOM is the name of the caller for error printing.
  249.  
  250. string
  251. get_working_directory (const string& for_whom)
  252. {
  253.   if (! follow_symbolic_links)
  254.     Vcurrent_directory = "";
  255.  
  256.   if (Vcurrent_directory.empty ())
  257.     {
  258.       Vcurrent_directory = octave_getcwd ();
  259.  
  260.       if (Vcurrent_directory.empty ())
  261.     warning ("%s: can't find current directory!", for_whom.c_str ());
  262.     }
  263.  
  264.   return Vcurrent_directory;
  265. }
  266.  
  267. // Do the work of changing to the directory NEWDIR.  Handle symbolic
  268. // link following, etc.
  269.  
  270. static int
  271. change_to_directory (const string& newdir)
  272. {
  273.   string tmp;
  274.  
  275.   if (follow_symbolic_links)
  276.     {
  277.       if (Vcurrent_directory.empty ())
  278.     get_working_directory ("cd_links");
  279.  
  280.       if (Vcurrent_directory.empty ())
  281.     tmp = newdir;
  282.       else
  283.     tmp = make_absolute (newdir, Vcurrent_directory);
  284.  
  285.       // Get rid of trailing `/'.
  286.  
  287.       size_t len = tmp.length ();
  288.  
  289.       if (len > 1)
  290.     {
  291.       if (tmp[--len] == '/')
  292.         tmp.resize (len);
  293.     }
  294.  
  295.       if (octave_chdir (tmp) < 0)
  296.     return 0;
  297.       else
  298.     {
  299.       Vcurrent_directory = tmp;
  300.       return 1;
  301.     }
  302.     }
  303.   else
  304.     return (octave_chdir (newdir) < 0) ? 0 : 1;
  305. }
  306.  
  307. static int
  308. octave_change_to_directory (const string& newdir)
  309. {
  310.   int cd_ok = change_to_directory (newdir);
  311.  
  312.   if (cd_ok)
  313.     do_external_plotter_cd (newdir);
  314.   else
  315.     error ("%s: %s", newdir.c_str (), strerror (errno));
  316.  
  317.   return cd_ok;
  318. }
  319.  
  320. DEFUN_TEXT (cd, args, ,
  321.   "cd [dir]\n\
  322. \n\
  323. change current working directory\n\
  324. if no arguments are given, the current directory is changed to the\n\
  325. users home directory")
  326. {
  327.   octave_value_list retval;
  328.  
  329.   int argc = args.length () + 1;
  330.  
  331.   string_vector argv = args.make_argv ("cd");
  332.  
  333.   if (error_state)
  334.     return retval;
  335.  
  336.   if (argc > 1)
  337.     {
  338.       string dirname = oct_tilde_expand (argv[1]);
  339.  
  340.       if (dirname.length () > 0
  341.       && ! octave_change_to_directory (dirname))
  342.     {
  343.       return retval;
  344.     }
  345.     }
  346.   else
  347.     {
  348.       if (Vhome_directory.empty ()
  349.       || ! octave_change_to_directory (Vhome_directory))
  350.     {
  351.       return retval;
  352.     }
  353.     }
  354.  
  355.   string directory = get_working_directory ("cd");
  356.   bind_builtin_variable ("PWD", directory, 1);
  357.  
  358.   return retval;
  359. }
  360.  
  361. DEFALIAS (chdir, cd);
  362.  
  363. // Get a directory listing.
  364.  
  365. static void
  366. cleanup_iprocstream (void *p)
  367. {
  368.   delete (iprocstream *) p;
  369. }
  370.  
  371. DEFUN_TEXT (ls, args, ,
  372.   "ls [options]\n\
  373. \n\
  374. print a directory listing")
  375. {
  376.   octave_value_list retval;
  377.  
  378.   int argc = args.length () + 1;
  379.  
  380.   string_vector argv = args.make_argv ("ls");
  381.  
  382.   if (error_state)
  383.     return retval;
  384.  
  385.   ostrstream ls_buf;
  386.  
  387.   ls_buf << "ls -C ";
  388.   for (int i = 1; i < argc; i++)
  389.     ls_buf << oct_tilde_expand (argv[i]) << " ";
  390.  
  391.   ls_buf << ends;
  392.   char *ls_command = ls_buf.str ();
  393.  
  394.   iprocstream *cmd = new iprocstream (ls_command);
  395.  
  396.   delete [] ls_command;
  397.  
  398.   add_unwind_protect (cleanup_iprocstream, cmd);
  399.  
  400.   if (cmd && *cmd)
  401.     {
  402.       int ch;
  403.       while ((ch = cmd->get ()) != EOF)
  404.     octave_stdout << (char) ch;
  405.     }
  406.   else
  407.     error ("couldn't start process for ls!");
  408.  
  409.   run_unwind_protect ();
  410.  
  411.   return retval;
  412. }
  413.  
  414. DEFALIAS (dir, ls);
  415.  
  416. DEFUN (pwd, , nargout,
  417.   "pwd (): print current working directory")
  418. {
  419.   octave_value_list retval;
  420.   string directory;
  421.  
  422.   if (verbatim_pwd)
  423.     {
  424.       directory = octave_getcwd ();
  425.  
  426.       if (directory.empty ())
  427.     warning ("pwd: can't find working directory!");
  428.     }
  429.   else
  430.     directory = get_working_directory ("pwd");
  431.  
  432.   if (! directory.empty ())
  433.     {
  434.       if (nargout == 0)
  435.     octave_stdout << directory << "\n";
  436.       else
  437.     retval = directory;
  438.     }
  439.  
  440.   return retval;
  441. }
  442.  
  443. DEFUN (readdir, args, ,
  444.   "[FILES, STATUS, MSG] = readdir (NAME)\n\
  445. \n\
  446. Return an array of strings containing the list of all files in the\n\
  447. named directory in FILES, or an empty matrix if an error occurs\n\
  448. \n\
  449. If successful, STATUS is 0 and MSG is an empty string.  Otherwise,\n\
  450. STATUS is nonzero and MSG contains a system-dependent error message.")
  451. {
  452.   octave_value_list retval;
  453.  
  454.   retval(2) = string ();
  455.   retval(1) = -1.0;
  456.   retval(0) = Matrix ();
  457.  
  458.   if (args.length () == 1)
  459.     {
  460.       string dirname = args(0).string_value ();
  461.  
  462.       if (error_state)
  463.     gripe_wrong_type_arg ("readdir", args(0));
  464.       else
  465.     {
  466.       dir_entry dir (oct_tilde_expand (dirname));
  467.  
  468.       if (dir)
  469.         {
  470.           string_vector dirlist = dir.read ();
  471.           retval(0) = dirlist.qsort ();
  472.           retval(1) = 0.0;
  473.         }
  474.       else
  475.         {
  476.           retval(2) = dir.error ();
  477.         }
  478.     }
  479.     }
  480.   else
  481.     print_usage ("readdir");
  482.  
  483.   return retval;
  484. }
  485.  
  486. // XXX FIXME XXX -- should probably also allow second arg to specify
  487. // mode.
  488.  
  489. DEFUN (mkdir, args, ,
  490.   "[STATUS, MSG] = mkdir (NAME)\n\
  491. \n\
  492. Create the directory named by NAME.\n\
  493. \n\
  494. If successful, STATUS is 0 and MSG is an empty string.  Otherwise,\n\
  495. STATUS is nonzero and MSG contains a system-dependent error message.")
  496. {
  497.   octave_value_list retval;
  498.  
  499.   retval(1) = string ();
  500.   retval(0) = -1.0;
  501.  
  502.   if (args.length () == 1)
  503.     {
  504.       string dirname = args(0).string_value ();
  505.  
  506.       if (error_state)
  507.     gripe_wrong_type_arg ("mkdir", args(0));
  508.       else
  509.     {
  510.       string msg;
  511.  
  512.       int status = oct_mkdir (oct_tilde_expand (dirname),
  513.                   0777, msg);
  514.  
  515.       retval(0) = (double) status;
  516.  
  517.       if (status < 0)
  518.         retval(1) = msg;
  519.     }
  520.     }
  521.   else
  522.     print_usage ("mkdir");
  523.  
  524.   return retval;
  525. }
  526.  
  527. DEFUN (rmdir, args, ,
  528.   "[STATUS, MSG] = rmdir (NAME)\n\
  529. \n\
  530. Remove the directory named by NAME.\n\
  531. \n\
  532. If successful, STATUS is 0 and MSG is an empty string.  Otherwise,\n\
  533. STATUS is nonzero and MSG contains a system-dependent error message.")
  534. {
  535.   octave_value_list retval;
  536.  
  537.   retval(1) = string ();
  538.   retval(0) = -1.0;
  539.  
  540.   if (args.length () == 1)
  541.     {
  542.       string dirname = args(0).string_value ();
  543.  
  544.       if (error_state)
  545.     gripe_wrong_type_arg ("rmdir", args(0));
  546.       else
  547.     {
  548.       string msg;
  549.  
  550.       int status = oct_rmdir (oct_tilde_expand (dirname), msg);
  551.  
  552.       retval(0) = (double) status;
  553.  
  554.       if (status < 0)
  555.         retval(1) = msg;
  556.     }
  557.     }
  558.   else
  559.     print_usage ("rmdir");
  560.  
  561.   return retval;
  562. }
  563.  
  564. DEFUN (rename, args, ,
  565.   "[STATUS, MSG] = rename (FROM, TO)\n\
  566. \n\
  567. Rename a file.\n\
  568. \n\
  569. If successful, STATUS is 0 and MSG is an empty string.  Otherwise,\n\
  570. STATUS is nonzero and MSG contains a system-dependent error message.")
  571. {
  572.   octave_value_list retval;
  573.  
  574.   retval(1) = string ();
  575.   retval(0) = -1.0;
  576.  
  577.   if (args.length () == 2)
  578.     {
  579.       string from = args(0).string_value ();
  580.  
  581.       if (error_state)
  582.     gripe_wrong_type_arg ("rename", args(0));
  583.       else
  584.     {
  585.       string to = args(1).string_value ();
  586.  
  587.       if (error_state)
  588.         gripe_wrong_type_arg ("rename", args(1));
  589.       else
  590.         {
  591.           string msg;
  592.  
  593.           int status = oct_rename (from, to, msg);
  594.  
  595.           retval(0) = (double) status;
  596.  
  597.           if (status < 0)
  598.         retval(1) = msg;
  599.         }
  600.     }
  601.     }
  602.   else
  603.     print_usage ("rename");
  604.  
  605.   return retval;
  606. }
  607.  
  608. DEFUN (glob, args, ,
  609.   "glob (PATTERN)\n\
  610. \n\
  611. Given an array of strings in PATTERN, return the list of file names\n\
  612. that any of them, or an empty string if no patterns match.  Tilde\n\
  613. expansion is performed on each of the patterns before looking for\n\
  614. matching file names.")
  615. {
  616.   octave_value retval;
  617.  
  618.   if (args.length () == 1)
  619.     {
  620.       string_vector pat = args(0).all_strings ();
  621.  
  622.       if (error_state)
  623.     gripe_wrong_type_arg ("glob", args(0));
  624.       else
  625.     {
  626.       glob_match pattern (oct_tilde_expand (pat));
  627.  
  628.       string_vector list = pattern.glob ();
  629.  
  630.       if (list.empty ())
  631.         retval = "";
  632.       else
  633.         retval = list;
  634.     }
  635.     }
  636.   else
  637.     print_usage ("glob");
  638.  
  639.   return retval;
  640. }
  641.  
  642. DEFUN (fnmatch, args, ,
  643.   "fnmatch (PATTERN, STRING)\n\
  644. \n\
  645. Return 1 or zero for each element of STRING that matches any of the\n\
  646. elements of the string array PATTERN, using the rules of filename\n\
  647. pattern matching.")
  648. {
  649.   octave_value retval;
  650.  
  651.   if (args.length () == 2)
  652.     {
  653.       string_vector pat = args(0).all_strings ();
  654.       string_vector str = args(1).all_strings ();
  655.  
  656.       if (error_state)
  657.     gripe_wrong_type_arg ("fnmatch", args(0));
  658.       else
  659.     {
  660.       glob_match pattern (oct_tilde_expand (pat));
  661.  
  662.       Array<bool> tmp = pattern.match (str);
  663.  
  664.       int n = tmp.length ();
  665.  
  666.       ColumnVector result (n);
  667.  
  668.       for (int i = 0; i < n; i++)
  669.         result(i) = tmp(i);
  670.  
  671.       retval = octave_value (result, true);
  672.     }
  673.     }
  674.   else
  675.     print_usage ("fnmatch");
  676.  
  677.   return retval;
  678. }
  679.  
  680. static int
  681. pwd (void)
  682. {
  683.   int status = 0;
  684.  
  685.   string s = builtin_string_variable ("PWD");
  686.  
  687.   if (s.empty ())
  688.     {
  689.       gripe_invalid_value_specified ("PWD");
  690.       status = -1;
  691.     }
  692.   else
  693.     Vcurrent_directory = s;
  694.  
  695.   return status;
  696. }
  697.  
  698. void
  699. symbols_of_dirfns (void)
  700. {
  701.   DEFCONST (PWD, get_working_directory ("initialize_globals"), 0, pwd,
  702.     "current working directory");
  703. }
  704.  
  705. /*
  706. ;;; Local Variables: ***
  707. ;;; mode: C++ ***
  708. ;;; End: ***
  709. */
  710.